/**
 * 
 */
package ga.nqueens;

import ga.tsp.SwapMutation;

import java.util.List;

import org.jheuristics.Individual;
import org.jheuristics.ga.DefaultGAConfig;
import org.jheuristics.ga.DoubleFitness;
import org.jheuristics.ga.Evolver;
import org.jheuristics.ga.GAConfig;
import org.jheuristics.ga.GAStatus;
import org.jheuristics.ga.Population;
import org.jheuristics.ga.SimpleBulkFitnessEvaluator;
import org.jheuristics.ga.SimpleEvolver;
import org.jheuristics.ga.operators.CompositeOperator;
import org.jheuristics.ga.operators.ReproductionOperator;
import org.jheuristics.ga.operators.SelectionOperator;
import org.jheuristics.ga.operators.StatusPopulationChooser;
import org.jheuristics.ga.operators.probabilities.ConstantProbability;
import org.jheuristics.ga.operators.rates.ConstantRate;
import org.jheuristics.ga.operators.selectors.AllIndividualsSelector;
import org.jheuristics.ga.operators.selectors.BestIndividualsSelector;
import org.jheuristics.ga.operators.selectors.RandomSelector;
import org.jheuristics.ga.operators.selectors.StochasticUniversalSampingSelector;
import org.jheuristics.ga.scalers.ScalersFactory;
import org.jheuristics.util.Condition;
import org.jheuristics.util.DefaultRandomGenerator;
import org.jheuristics.util.conditions.AndCondition;
import org.jheuristics.util.conditions.MaxGenerationCondition;

/**
 * @author thiago
 *
 */
public class NQueensGA {

	public static void main(String[] args) {
		
		int maxGeneration = Integer.parseInt(args[0]);
		double mutationProbability = Double.parseDouble(args[1]);
		double xoverProbability = Double.parseDouble(args[2]);
		int dimension = Integer.parseInt(args[3]);
		int populacao = Integer.parseInt(args[4]);
			
		CompositeOperator operator = new CompositeOperator();
		
		operator.addOperator(new SelectionOperator(
									new ConstantRate(25),
									new StochasticUniversalSampingSelector(
											ScalersFactory.noScaler()),
									StatusPopulationChooser.CURRENT,
									false,
									StatusPopulationChooser.AVALIABLE,
									false));
		
		operator.addOperator(new ReproductionOperator(
									new ConstantRate(49),
									new RandomSelector(), 
									new NQueensCycleXOver(new ConstantProbability(xoverProbability)), 
									StatusPopulationChooser.AVALIABLE,
									false,
									StatusPopulationChooser.SELECTED,
									false));
		
		operator.addOperator(new ReproductionOperator(
									new ConstantRate(0),
									new AllIndividualsSelector(), 
									new SwapMutation(new ConstantProbability(mutationProbability)), 
									StatusPopulationChooser.SELECTED,
									false,
									StatusPopulationChooser.SELECTED,
									true));
		
		operator.addOperator(new SelectionOperator(
								new ConstantRate(1), 
								new BestIndividualsSelector(), 
								StatusPopulationChooser.CURRENT, 
								false,
								StatusPopulationChooser.SELECTED,
								false));
		
		GAConfig config = new DefaultGAConfig(
									new NQueensIndividualFactory(dimension),
									operator, 
									new SimpleBulkFitnessEvaluator(
											new NQueensFitnessEvaluator()), 
									new DefaultRandomGenerator());
		
		Evolver evolver = new SimpleEvolver(config, populacao);
		evolver.evolve(
			new AndCondition(
					new Condition() {
						@Override
						public boolean check(Object obj) {
							
							GAStatus status = ((GAStatus)((Object[])obj)[0]);
							
							Population currentPopulation = status.getCurrentPopulation();
							Individual individual = currentPopulation.getIndividual(0);
							
							Board board = new Board( ((List<Integer>)individual.getGens()));
							int hits = board.hits();
							return hits != 0;
						}
					},
				new MaxGenerationCondition(maxGeneration))				 
			);		
		
		GAStatus status = evolver.getEvolutionStatus();
		Population currentPopulation = status.getCurrentPopulation();
		Individual individual = currentPopulation.getIndividual(0);
		int age = status.getEvolutionAge();
		System.out.println("age: "+age+" "+((long)-((DoubleFitness) individual.getFitness()).toDouble()) + " " + individual.getGens());
		
	}
		
}